package mygame;

import Monster.SimpleMonster;
import Utility.SceneLoader;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
import com.jme3.texture.Texture;

/**
 * test
 * @author normenhansen
 */
public class Main extends SimpleApplication implements ActionListener{

    private Spatial sceneModel;
    private BulletAppState bulletAppState;
    private RigidBodyControl landscape;
    private CharacterControl player;
    private Vector3f walkDirection = new Vector3f();
    private boolean left = false;
    private boolean right = false;
    private boolean forward = false;
    private boolean backward = false;
    private Sphere sphere;
    private Material stone_mat;
    private SimpleMonster simpleMonster;
    private SceneLoader sceneLoader;

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }
    
   
   

    @Override
    public void simpleInitApp() {
        sphere = new Sphere(32, 32, 0.4f, true, false);
        sphere.setTextureMode(TextureMode.Projected);
        stone_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG");
        key2.setGenerateMips(true);
        Texture tex2 = assetManager.loadTexture(key2);
        stone_mat.setTexture("ColorMap", tex2);
         /*Creates the UserInterface*/
        initCrossHairs(); //Creates the crosshairs
        /*Creates the world and the player*/
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
        viewPort.setBackgroundColor(new ColorRGBA(0.7f,0.8f,1f,1f));
        flyCam.setMoveSpeed(100);
        initKeys();
        setUpLight();
        assetManager.registerLocator("town.zip",ZipLocator.class.getName());
        sceneModel = assetManager.loadModel("main.scene");
        sceneModel.setLocalScale(2f);
        CollisionShape sceneShape = CollisionShapeFactory.createMeshShape((Node) sceneModel);
        landscape = new RigidBodyControl(sceneShape,0);
        
        //Simple Monster addition
        simpleMonster = new SimpleMonster("elephant",20,assetManager.loadModel("Models/Elephant/Elephant.mesh.xml"));
        CollisionShape elephant = CollisionShapeFactory.createMeshShape((Node)simpleMonster.getModel());
        RigidBodyControl elephantControl = new RigidBodyControl(elephant,0);
        rootNode.attachChild(simpleMonster.getModel());
        bulletAppState.getPhysicsSpace().add(elephantControl);
        
        /*SceneLoader
        sceneLoader = new SceneLoader(assetManager, this, bulletAppState);
        sceneLoader.setScene("town.zip","main.scene");
        */
        
        
        sceneModel.addControl(landscape);
        CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f,6f,1);
        player = new CharacterControl(capsuleShape,0.05f);
        player.setJumpSpeed(20);
        player.setFallSpeed(30);
        player.setGravity(30);
        player.setPhysicsLocation(new Vector3f(0,10,0));
        
        rootNode.attachChild(sceneModel);
        bulletAppState.getPhysicsSpace().add(landscape);
        bulletAppState.getPhysicsSpace().add(player);
        
        
        
       
    }

    @Override
    public void simpleUpdate(float tpf) {
        Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
        Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
        walkDirection.set(0,0,0);
        if(left) { walkDirection.addLocal(camLeft);}
        if(right) {walkDirection.addLocal(camLeft.negate());}
        if(forward){walkDirection.addLocal(camDir);}
        if(backward){walkDirection.addLocal(camDir.negate());}
        player.setWalkDirection(walkDirection);
        cam.setLocation(player.getPhysicsLocation());
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
    
    /**
     * Creates and controls custom keyboard initialization
     */
    private void initKeys(){
        inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("Right",new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("Jump",new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addMapping("Shoot",new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addListener(this,"Left");
        inputManager.addListener(this,"Right");
        inputManager.addListener(this,"Forward");
        inputManager.addListener(this,"Backward");
        inputManager.addListener(this,"Jump");
        inputManager.addListener(this,"Shoot");
        
    }
    
    private void setUpLight(){
        AmbientLight al = new AmbientLight();
        al.setColor(ColorRGBA.White.mult(1.3f));
        rootNode.addLight(al);
        
        DirectionalLight dl = new DirectionalLight();
        dl.setColor(ColorRGBA.White);
        dl.setDirection(new Vector3f(2.8f,-2.8f,-2.9f).normalizeLocal());
        rootNode.addLight(dl);
    }

    public void onAction(String binding, boolean value, float tpf) {
         if (binding.equals("Left")) {
                left = value;
         } else if (binding.equals("Right")) {
                right = value;
         } else if (binding.equals("Forward")) {
                forward = value;
         } else if (binding.equals("Backward")) {
                backward = value;
         } else if (binding.equals("Jump")) {
                player.jump();
         } else if (binding.equals("Shoot")&&!value){
                makeCannonBall();
         }
  }
    private void initCrossHairs(){
        guiNode.detachAllChildren();
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText ch = new BitmapText(guiFont,false);
        ch.setSize(guiFont.getCharSet().getRenderedSize()*2);
        ch.setText("+");//crosshairs
        ch.setLocalTranslation(settings.getWidth()/2-guiFont.getCharSet().getRenderedSize()/3*2,settings.getHeight()/2+ch.getLineHeight()/2,0);
        guiNode.attachChild(ch);
    }
    
       public void makeCannonBall() {
           

    /** Create a cannon ball geometry and attach to scene graph. */
    Geometry ball_geo = new Geometry("cannon ball", sphere);
    ball_geo.setMaterial(stone_mat);
    rootNode.attachChild(ball_geo);
    /** Position the cannon ball  */
    Vector3f camLocation = this.getCamera().getLocation();
    ball_geo.setLocalTranslation(this.getCamera().getDirection().scaleAdd(3, camLocation));
    /** Make the ball physcial with a mass > 0.0f */
   RigidBodyControl  ball_phy = new RigidBodyControl(1f);
    /** Add physical ball to physics space. */
    ball_geo.addControl(ball_phy);
    bulletAppState.getPhysicsSpace().add(ball_phy);
    /** Accelerate the physcial ball to shoot it. */
    ball_phy.setLinearVelocity(cam.getDirection().clone().mult(75));
  }

}
